/**
 * @File Name: threadpool.h
 * @brief  线程池类的实现
 * @Author : beyon_sir email:caoboyang.chn@gmail.com
 * @Version : 1.0
 * @Create Date : 2022-11-20
 * 
 */
#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>
#include <functional>

/// @brief 线程池类
class ThreadPool {
public:
    /// @brief 初始化所有线程 explicit防止隐式转换
    /// @param threadCount 
    explicit ThreadPool(size_t threadCount = 8): pool_(std::make_shared<Pool>()) {
            assert(threadCount > 0); // 测试用
            // 创建 threadCount 数量的子线程
            for(size_t i = 0; i < threadCount; i++) {
                std::thread([pool = pool_] {
                    std::unique_lock<std::mutex> locker(pool->mtx);
                    while(true) {
                        // 判断队列是否为空
                        if(!pool->tasks.empty()) {
                            // 从任务队列中取一个任务
                            auto task = std::move(pool->tasks.front()); // 转换为右值引用 之前在队列中的任务没有用了
                            // 移除已取出的任务
                            pool->tasks.pop();
                            locker.unlock();    // 解除锁 临界区已执行完毕(从消息队列拿取、消除任务)
                            task();             // 执行处理逻辑
                            locker.lock();      // 获取锁 开始执行下一循环的对临界区的操作(没有获得就阻塞)
                        } 
                        // 如果线程池关闭 退出循环 销毁线程
                        else if(pool->isClosed) break;
                        // 条件变量 等待生产者(主线程 IO逻辑) 输入新的任务 等待唤醒 临时解锁
                        else pool->cond.wait(locker); 
                    }
                }
                ).detach(); // 线程分离
            }
    }

    /// @brief 设置默认构造函数
    ThreadPool() = default;
    /// @brief 移动构造函数 (default)
    /// @param  
    ThreadPool(ThreadPool&&) = default;
    
    /// @brief 线程池销毁
    ~ThreadPool() {
        if(static_cast<bool>(pool_)) {
            {
                std::lock_guard<std::mutex> locker(pool_->mtx);
                // 关闭线程池
                pool_->isClosed = true;
            }
            // 唤醒所有等待的线程 并执行销毁
            pool_->cond.notify_all();
        }
    }

    /// @brief 当主线程完成对client HTTP request的读入后 
    /// 将任务注册放入任务队列中 等待子线程领取任务完成后续流程(对HTTP request的解析 以及生成HTTP response)
    /// @tparam F 
    /// @param task 
    template<class F>
    void AddTask(F&& task) {
        {
            // lock_guard 创建时加锁，析构时解锁 当对象离开作用域时自动解锁
            std::lock_guard<std::mutex> locker(pool_->mtx);
            pool_->tasks.emplace(std::forward<F>(task));
        }
        // 基于条件变量通知子线程有新任务进入队列中，激活一个子线程
        pool_->cond.notify_one(); 
    }

private:
    /// @brief 结构体Pool
    struct Pool {
        std::mutex mtx;                             // 互斥锁: 在执行临界区的代码 访问临界资源tasks时，为了线程同步所需互斥量(锁)
        std::condition_variable cond;               // 条件变量: 当容器中不再有物品时，消费者会堵塞；生产者在生产完一个物品后，会唤醒消费者继续进行消费。
        bool isClosed;                              // 是否关闭线程池的标志(~ThreadPool())
        std::queue<std::function<void()>> tasks;    // 任务队列(保存任务)
    };
    std::shared_ptr<Pool> pool_;                    // 线程池: 每个子线程获取该共享指针来访问其中的资源
};


#endif // !THREADPOOL_H